//
//  UIListView.m
//  Vgo
//
//  Created by 21CN Vgo on 11-4-6.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "UIListView.h"
#import "UIListViewCell.h"
#import <QuartzCore/CAAnimation.h>
#import <QuartzCore/CAMediaTimingFunction.h>
#import <QuartzCore/QuartzCore.h>
#import "UIUtil.h"

@interface UIListView (private)

- (BOOL)IsRectVisible:(CGRect)rect;
- (void)Initialize;
- (CGRect)selfBounds;

- (void)calRowAndColNum;
- (void)updateEdges;
- (void)updateScrollSize;
- (CGSize)scrollSize;


- (void)removeInVisibleCellsWithAnimate:(BOOL)animate;
- (void)saveReuseCell:(UIListViewCell *)cell;
- (void)displayVisibleCellsWithAnimate:(BOOL)animate;

- (CGRect)cellFrameAtVisualRect:(CGRect)boundRect forCell:(UIListViewCell *)cell;
- (NSIndexPath *)validIndexPathAtPoint:(CGPoint)point; 
- (BOOL)IsIndexPathValid:(NSIndexPath *)indexPath;

-(CGRect)topLeftRectForIndexPath:(NSIndexPath *)indexPath;
-(CGRect)middleRectForIndexPath:(NSIndexPath *)indexPath;
-(CGRect)bottomRightRectForIndexPath:(NSIndexPath *)indexPath;

-(void)processSelectionForCell:(UIListViewCell *)cell;
-(void)processSelectionsForIndexPath:(NSIndexPath *)indexPath;
-(void)processSelections;
-(void)deselectIndexPath:(NSIndexPath *)indexPath cusDidDeselect:(BOOL)cusDidDeselect;

-(void)selectCell:(UIListViewCell *)cell;

-(void)insertCellAtIndex:(NSUInteger)index animated:(BOOL)animated;
-(void)deleteCellAtIndex:(NSUInteger)index animated:(BOOL)animated;
-(void)reloadCellAtIndex:(NSUInteger)index animated:(BOOL)animated;
-(NSIndexPath *)indexPathForIndex:(NSUInteger)index;
-(void)updateItemOriPositions;
-(void)processItemOperations;
-(ItemPosition *)positionItemAtIndex:(NSUInteger)index;

-(void)processEditing;
-(void)cancelSingleEditing;

-(void)startRotateAnimationAtCell:(UIListViewCell *)cell shortPress:(BOOL)shortPress;
-(void)stopRotateAnimationAtCell:(UIListViewCell *)cell;
-(void)startMoveAnimationAtCell:(UIListViewCell *)cell destFrame:(CGRect)destFrame moveOut:(BOOL)moveOut index:(NSUInteger)index;
-(void)startScaleAnimationAtCell:(UIListViewCell *)cell toRemove:(BOOL)toRemove;
-(void)stopScaleAnimationAtCell:(UIListViewCell *)cell;
/// UIView Animation delegate
- (void)willStartMoveAnimation:(NSString *)animationID context:(void *)context;
- (void)didStopMoveAnimation:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context;

-(void)AddLongPressRecognizerToCell:(UIListViewCell *)cell;
-(void)handleLongPress:(UILongPressGestureRecognizer*)longPressRecognizer;
-(BOOL)LongPressAlreadyAddToCell:(UIListViewCell *)cell;
-(void)AddPanGestureRecognizerToCell:(UIListViewCell *)cell;
-(void)handlePanGesture:(UIPanGestureRecognizer *)panGestureRecognizer;
-(BOOL)panGestureAlreadyAddToCell:(UIListViewCell *)cell;
-(void)AddShortPress;
-(void)handleShortPress:(UILongPressGestureRecognizer *)shortPressRecognizer;

-(IBAction)click_delete:(id)sender;
-(IBAction)cancel_delete:(id)sender;
-(void)AddDeleteButtonToCell:(UIListViewCell *)cell shortPress:(BOOL)shortPress;
-(void)RemoveDeleteButtonFromCell:(UIListViewCell *)cell;

//-(void)HandleEnterSingleEditMode;
//-(void)HandleCancelSingleEditMode;

-(CellRange *)visibleRange;

@end

@implementation UIListView

@synthesize dataSource = _dataSource;
@synthesize listViewDelegate = _listViewDelegate;
@synthesize rowHeight = _rowHeight;
@synthesize columnWidth = _columnWidth;
@synthesize backgroundView = _backgroundView;
@synthesize allowsSelection = _allowsSelection;
@synthesize allowsLongPressAnimation = _allowsLongPressAnimation;
@synthesize allowsPanGuestureEdit = _allowsPanGuestureEdit;
@synthesize editing = _editing;
@synthesize delImageName = _delImageName;
@synthesize allowsMultiSelection = _allowsMultiSelection;
@synthesize scrollInset = _scrollInset;

- (id)initWithFrame:(CGRect)frame {
    
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code.
		[self Initialize];
    } 
    return self;
}

- (void)setDelegate:(id <UIScrollViewDelegate>)delegate
{
	if (delegate != self)
		_outsideDelegate = delegate;
	
	[super setDelegate:self];
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code.
}
*/

// Subclasses can override it to perform additional actions when subviews are added. 
// This method is called in response to adding a subview using any of the relevant view methods.
//- (void)didAddSubview:(UIView *)subview
//{
//	[super didAddSubview:subview];
//}

// Subclasses can override it to perform additional actions whenever subviews are removed. 
// This method is called when the subview’s superview changes or when the subview is removed from the view hierarchy completely.
//- (void)willRemoveSubview:(UIView *)subview
//{
//	[super willRemoveSubview:subview];
//}

// Implement this method if you want your view to have a different default size than it normally would during resizing operations.
//- (CGSize)sizeThatFits:(CGSize)size
//{
//	return [super sizeThatFits:size];
//}

-(void)setFrame:(CGRect)rect
{
	if (!CGRectEqualToRect(rect, self.frame)) {
		_shoudRelayout = YES;
	}
	[super setFrame:rect];
}

// Implement this method if you need more precise control over the layout of your subviews than the autoresizing behaviors provide.
- (void)layoutSubviews
{
	[super layoutSubviews];
	
	if (_shoudRelayout) {
		[self reloadData];
		_shoudRelayout = NO;
	} 
	

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

	UITouch * touch = [touches anyObject];
	//NSLog(@"touchesBegan:%x", touch.view);
	if (touch.phase == UITouchPhaseBegan && _allowsSelection == YES) {
		if ([touch.view isKindOfClass:[UIListViewCell class]]) {
			UIListViewCell * cell = (UIListViewCell *)touch.view;
			NSIndexPath * indexPath = [self indexPathForCell:cell];
			NSNumber * index = [NSNumber numberWithUnsignedInteger:(indexPath.row * _numberOfColumns + [indexPath column])];
			if ([_selectedIndexes containsObject:index] == NO) {
				[cell setSelected:YES animated:NO];
			}
		}
	}

	[super touchesBegan:touches withEvent:event];
}
 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
	//UITouch * touch = [touches anyObject];
	//NSLog(@"touchesMoved:%x", touch.view);
	
	[super touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	
	UITouch * touch = [touches anyObject]; 
	//NSLog(@"touchesEnded:%x", touch.view);
	if (touch.phase == UITouchPhaseEnded && _allowsSelection == YES) {
		if ([touch.view isKindOfClass:[UIListViewCell class]]) {
			[self selectCell:(UIListViewCell *)touch.view];
		}
	}

	[super touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	UITouch * touch = [touches anyObject];
	//NSLog(@"touchesCancelled:%x", touch.view);
	if (touch.phase == UITouchPhaseCancelled && _allowsSelection == YES) {
		if ([touch.view isKindOfClass:[UIListViewCell class]]) {
			UIListViewCell * cell = (UIListViewCell *)touch.view;
			NSIndexPath * indexPath = [self indexPathForCell:cell];
			NSNumber * index = [NSNumber numberWithUnsignedInteger:(indexPath.row * _numberOfColumns + [indexPath column])];
			if ((_longPress == NO) && [_selectedIndexes containsObject:index] == NO) {
				[cell setSelected:NO animated:NO];
			}
		}
	}
	
	[super touchesCancelled:touches withEvent:event];

}

- (void)dealloc {
	
	SAFE_RELEASE(_backgroundView);
	SAFE_RELEASE(_reusableTableCells);
	SAFE_RELEASE(_visibleCells);
	
	SAFE_RELEASE(_singleEditingIndex);
	
	SAFE_RELEASE(_rowEdges);
	SAFE_RELEASE(_colEdges);
	
	SAFE_RELEASE(_selectedIndexes);
	SAFE_RELEASE(_pendingSelectionIndex);
	SAFE_RELEASE(_pendingDeselectionIndexes);
	
	SAFE_RELEASE(_removeCells);
	SAFE_RELEASE(_removeCellsAnimated);
	
	SAFE_RELEASE(_insertItems);
	SAFE_RELEASE(_reloadItems);
	SAFE_RELEASE(_insertItemsAnimated);
	SAFE_RELEASE(_changeItemOriginalPositions);
	SAFE_RELEASE(_itemOperations);
	
	SAFE_RELEASE(_delImageName);
	SAFE_RELEASE(_deleteButtons);
	
	SAFE_RELEASE(_visRange);
	
	self.dataSource = nil;
	self.listViewDelegate = nil;
	
	[super dealloc];
}

/// private
- (BOOL)IsRectVisible:(CGRect)rect
{
	//CGRect bound = [self selfBounds];
	BOOL bVisible = YES;
	if (rect.origin.x > self.bounds.origin.x + self.bounds.size.width || 
		rect.origin.y > self.bounds.origin.y + self.bounds.size.height ||
		rect.origin.x + rect.size.width < self.bounds.origin.x ||
		rect.origin.y + rect.size.height < self.bounds.origin.y) {
		bVisible = NO;
	}
	return bVisible;
}

#define DEFAULT_ROWHEIGHT 50.0
#define DEFAULT_COLUMNWIDTH 50.0
- (void)Initialize
{
	_rowHeight = DEFAULT_ROWHEIGHT;
	_columnWidth = DEFAULT_COLUMNWIDTH;
	_allowsSelection = YES;
	_allowsMultiSelection = NO;
	_allowsLongPressAnimation = NO;
	_allowsPanGuestureEdit = NO;
	_editing = NO;
	_singleEditingIndex = nil;
	_animating = NO;
	_reusableTableCells = [[NSMutableDictionary alloc] initWithCapacity:1];
	_visibleCells = [[NSMutableDictionary alloc] initWithCapacity:1];
	_numberOfRows = 0;
	_numberOfColumns = 0;
	_numberOfCells = 0;
	
	_rowEdges = [[NSMutableArray alloc] initWithCapacity:1];
	_colEdges = [[NSMutableArray alloc] initWithCapacity:1];
	
	_visRange = [[CellRange alloc] initWithLeft:0 top:0 right:0 bottom:0];
	
	_shoudRelayout = YES;
	
	_selectedIndexes = [[NSMutableArray alloc] initWithCapacity:1];
	_pendingSelectionIndex = nil;
	_pendingDeselectionIndexes = nil;
	_latestSelectRow = 0;
	_latestSelectColum = 0;
	
	_updateCount = 0;
	_removeCells = [[NSMutableArray alloc] initWithCapacity:1];
	_removeCellsAnimated = [[NSMutableArray alloc] initWithCapacity:1];
	_insertItems = [[NSMutableArray alloc] initWithCapacity:1];
	_reloadItems = [[NSMutableArray alloc] initWithCapacity:1];
	
	_insertItemsAnimated = [[NSMutableArray alloc] initWithCapacity:1];
	
	_changeItemOriginalPositions = [[NSMutableArray alloc] initWithCapacity:1];
	_itemOperations = [[NSMutableArray alloc] initWithCapacity:1];
	
	_longPress = NO;
	
	_delImageName = nil;
	_deleteButtons = [[NSMutableArray alloc] initWithCapacity:1];
	
	_scrollInset = UIEdgeInsetsZero;
	
	_backgroundView = [[UIView alloc] initWithFrame:self.bounds];
	
	self.listViewDelegate = nil;
	self.dataSource = nil;
//	_backgroundView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |
//									UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleHeight  | UIViewAutoresizingFlexibleBottomMargin;
	//_backgroundView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
	[self addSubview:_backgroundView];
	
	self.delegate = self;
	
}

- (CGRect)selfBounds
{
	return CGRectOffset(self.bounds, -self.contentOffset.x, -self.contentOffset.y);
}

- (void)calRowAndColNum
{
	if (_numberOfColumns > 0) {
		_numberOfRows = (_numberOfCells / _numberOfColumns);
		if (_numberOfCells%_numberOfColumns != 0) {
			_numberOfRows += 1;
		}
	} else if (_numberOfRows > 0) {
		_numberOfColumns = (_numberOfCells / _numberOfRows);
		if (_numberOfCells%_numberOfRows != 0) {
			_numberOfColumns += 1;
		}
	}
}

- (void)updateEdges
{
	[_colEdges removeAllObjects];
	CGFloat edgeX = 0;
	BOOL bCusColWid = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:widthForColumn:)]);
	[_colEdges addObject:[NSNumber numberWithFloat:edgeX]];
	for (NSUInteger i = 0; i < _numberOfColumns; i++) {
		edgeX += (bCusColWid ? [self.listViewDelegate listView:self widthForColumn:i] : _columnWidth);
		[_colEdges addObject:[NSNumber numberWithFloat:edgeX]];
	}
	
	[_rowEdges removeAllObjects];
	CGFloat edgeY = 0;
	BOOL bCusRowHei = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:heightForRow:)]);
	[_rowEdges addObject:[NSNumber numberWithFloat:edgeY]];
	for (NSUInteger i = 0; i < _numberOfRows; i++) {
		edgeY += (bCusRowHei ? [self.listViewDelegate listView:self heightForRow:i] : _rowHeight);
		[_rowEdges addObject:[NSNumber numberWithFloat:edgeY]];
	}

	//return CGRectMake(oriX - self.contentOffset.x, oriY - self.contentOffset.y, colWid, rowHei);
}

//#define SCROLLSIZECHANGEANIMATIONID @"ScrollSizeChangeAnimationID"
- (void)updateScrollSize
{
//	[UIView beginAnimations:SCROLLSIZECHANGEANIMATIONID context:nil];
//	[UIView setAnimationCurve:UIViewAnimationCurveLinear];
//	[UIView setAnimationDuration:0.2];
//	[UIView setAnimationWillStartSelector:@selector(willStartMoveAnimation:context:)];
//	[UIView setAnimationDidStopSelector:@selector(didStopMoveAnimation:finished:context:)];
//	[UIView setAnimationDelegate:self];
	
	self.contentSize = [self scrollSize];
	CGRect bound = [self selfBounds];
	[self.backgroundView setFrame:CGRectMake(bound.origin.x, bound.origin.y, self.contentSize.width, self.contentSize.height)];
	
//	[UIView commitAnimations];
}

-(CGSize)scrollSize
{
	//CGFloat width = 0;
	//if (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:widthForColumn:)]) {
//		for (NSInteger col = 0; col < _numberOfColumns; col++) {
//			width += [self.listViewDelegate listView:self widthForColumn:col];
//		}	
//	} else {
//		width = _columnWidth * _numberOfColumns;
//	}
//
//	CGFloat height = 0;
//	if (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:heightForRow:)]) {
//		for (NSInteger row = 0; row < _numberOfRows; row++) {
//			height += [self.listViewDelegate listView:self heightForRow:row];
//		}
//	} else {
//		height = _rowHeight * _numberOfRows;
//	}

//	return CGSizeMake(width, height);
	NSNumber * width = [_colEdges lastObject];
	NSNumber * height = [_rowEdges lastObject];
	return CGSizeMake(width ? [width floatValue] : 0.0, height ? [height floatValue] : 0.0);
	
}

- (void)removeInVisibleCellsWithAnimate:(BOOL)animate
{
	//NSLog(@"removeInVisibleCellsWithAnimate: %.1f", [[NSDate date] timeIntervalSince1970]);
	for (UIListViewCell * cell in _removeCells) {
		[cell removeFromSuperview];
	}
	[_removeCells removeAllObjects];
	
	for (UIListViewCell * cell in _removeCellsAnimated) {
		[self startScaleAnimationAtCell:cell toRemove:YES];
	}
	
	NSArray * indexes = [_visibleCells allKeys];
	for (NSNumber * index in indexes) {
		NSIndexPath * indexPath = [self indexPathForIndex:[index unsignedIntegerValue]];
		CGRect rect = [self rectForCellAtIndexPath:indexPath];
		if ([self IsRectVisible:rect] == NO) {
			UIListViewCell * cell = [_visibleCells objectForKey:index];
			if (animate) {
				CGRect cellFrame = [self cellFrameAtVisualRect:rect forCell:cell];
				ItemPosition * item = [self positionItemAtIndex:[index unsignedIntegerValue]];
				if (item == nil) {
					[cell setFrame:cellFrame];
				} else {
					CGRect oriCellFrame = [self cellFrameAtVisualRect:item.oriRect forCell:cell];
					[cell setFrame:oriCellFrame];
					[self startMoveAnimationAtCell:cell destFrame:cellFrame moveOut:YES index:[index unsignedIntegerValue]];
					[_changeItemOriginalPositions removeObject:item];
				}

			}
			else {
				[cell removeFromSuperview];
				[self saveReuseCell:cell];
				[_visibleCells removeObjectForKey:index];
			}
		}
	}
}

- (void)saveReuseCell:(UIListViewCell *)cell
{
	if (cell.editing == YES) {
		[self stopRotateAnimationAtCell:cell];
		[self RemoveDeleteButtonFromCell:cell];
		[cell setEditing:NO];
	} 
	
	/// single select
	[cell setSelected:NO animated:NO];
	
	if ([cell reuseIdentifier] != nil && [[cell reuseIdentifier] length] > 0) {
		NSMutableArray * existCells = [_reusableTableCells objectForKey:[cell reuseIdentifier]];
		if (existCells == nil) {
			NSMutableArray * cells = [NSMutableArray arrayWithCapacity:1];
			[cells addObject:cell];
			[_reusableTableCells setObject:cells forKey:[cell reuseIdentifier]];
		}else {
			[existCells addObject:cell];
		}
	}
}

- (void)displayVisibleCellsWithAnimate:(BOOL)animate
{
	//NSLog(@"displayVisibleCellsWithAnimate: %.1f", [[NSDate date] timeIntervalSince1970]);
	if (self.dataSource != nil) {
		//CellRange * visRange = [self visibleRange];
		//NSLog(@"left: %d, right: %d, top: %d, bottom: %d", visRange.left, visRange.right, visRange.top, visRange.bottom);
		for (NSInteger row = _visRange.top; row <= _visRange.bottom; row++) {
			for (NSInteger col = _visRange.left; col <= _visRange.right; col++) {
				NSNumber * index = [NSNumber numberWithUnsignedInteger:(row * _numberOfColumns + col)];
				if ([index unsignedIntegerValue] < _numberOfCells) {
					NSIndexPath * indexPath = [NSIndexPath indexPathForRow:row inColumn:col];
					CGRect rect = [self rectForCellAtIndexPath:indexPath];
					if ([self IsRectVisible:rect]) {
						UIListViewCell * existCell = [_visibleCells objectForKey:index];
						if (existCell) {
//							if ([_listViewDelegate respondsToSelector:@selector(listView:willDisplayCell:atIndexPath:)]) {
//								[_listViewDelegate listView:self willDisplayCell:existCell atIndexPath:indexPath];
//							}
							CGRect cellFrame = [self cellFrameAtVisualRect:rect  forCell:existCell];
							if (!CGRectEqualToRect(cellFrame, existCell.frame)) {
								if (_shoudRelayout == YES) {
									[existCell setFrame:cellFrame];
								} else {
									[self startMoveAnimationAtCell:existCell 
														 destFrame:cellFrame
														   moveOut:NO 
															 index:[index unsignedIntegerValue]];
									//[existCell setFrame:cellFrame];
								}
							} 
						} else {
							UIListViewCell * cell = [self.dataSource listView:self cellAtIndexPath:indexPath];
							if (_allowsLongPressAnimation == YES) {
								[self AddLongPressRecognizerToCell:cell];
							}
							if (_allowsPanGuestureEdit == YES) {
								[self AddPanGestureRecognizerToCell:cell];
							}
							
							if (cell != nil) {
								CGRect cellFrame = [self cellFrameAtVisualRect:rect forCell:cell];
								if (animate) {
									if ([_insertItemsAnimated containsObject:index]) {
										[_insertItemsAnimated removeObject:index];
										[self startScaleAnimationAtCell:cell toRemove:NO];
									} else {
										ItemPosition * item = [self positionItemAtIndex:[index unsignedIntegerValue]];
										if (item == nil) {
											[cell setFrame:cellFrame];
										} else {
											CGRect oriCellFrame = [self cellFrameAtVisualRect:item.oriRect forCell:cell]; 
											[cell setFrame:oriCellFrame];
											[self startMoveAnimationAtCell:cell 
																 destFrame:cellFrame 
																   moveOut:NO 
																	 index:[index unsignedIntegerValue]];
											
											[_changeItemOriginalPositions removeObject:item];
										}

									}
								}
								[cell setFrame:cellFrame];
								
								if ([_selectedIndexes containsObject:index]) {
									[cell setSelected:YES animated:NO];
								}
								if (_editing) {
									[self startRotateAnimationAtCell:cell shortPress:NO];
								} else {
									[self stopRotateAnimationAtCell:cell];
									if ([_singleEditingIndex isEqualToNumber:index]) {
										[self startRotateAnimationAtCell:cell shortPress:YES];
										[self AddShortPress];
									}
								}
								
								[cell setEditing:_editing animated:_animating];
								
								[self addSubview:cell];
								
								
								[_visibleCells setObject:cell forKey:index];
							}
						}

					} 
				}
			}
		}
	}
}

- (CGRect)cellFrameAtVisualRect:(CGRect)boundRect forCell:(UIListViewCell *)cell
{
	// initialize to fill up
//	CGFloat oriX = boundRect.origin.x + self.contentOffset.x;
//	CGFloat oriY = boundRect.origin.y + self.contentOffset.y;
	CGFloat oriX = boundRect.origin.x;
	CGFloat oriY = boundRect.origin.y;
	CGFloat width = boundRect.size.width;
	CGFloat height = boundRect.size.height;
	
//	CGFloat centerX = oriX + width / 2;
//	CGFloat centerY = oriY + height / 2;
	
	if (cell != nil) {
		// center
		if (cell.autoresizingMask == UIViewAutoresizingNone) {
			CGFloat xOff = (width - cell.frame.size.width) / 2;
			CGFloat yOff = (height - cell.frame.size.height) / 2;
			oriX += xOff;
			oriY += yOff;
			width = cell.frame.size.width;
			height = cell.frame.size.height;
		} else {
			if (cell.autoresizingMask & UIViewAutoresizingFlexibleWidth) {
				// flexible width
				if (!(cell.autoresizingMask & UIViewAutoresizingFlexibleLeftMargin)) {
					// fixed left
					if (cell.autoresizingMask & UIViewAutoresizingFlexibleRightMargin) {
						// flexible right
						width = cell.frame.size.width + (width - cell.frame.size.width) / 2; 
					} 
//					else 
//					{
//						// horizontal fill up
//					}
				}
				else {
					// flexible left
					CGFloat xOff = (width - cell.frame.size.width) / 2;
					oriX += xOff;
					width -= xOff;
				}
			} else {
				// fixed width 
				if (!(cell.autoresizingMask & UIViewAutoresizingFlexibleLeftMargin)) {
					// fixed left
					width = cell.frame.size.width;
				} else {
					if (!(cell.autoresizingMask & UIViewAutoresizingFlexibleRightMargin)) {
						// fixed right
						oriX += (width - cell.frame.size.width);
						width = cell.frame.size.width;
					} else {
						// horizontal middle
						CGFloat xOff = (width - cell.frame.size.width) / 2;
						oriX += xOff;
						width = cell.frame.size.width;
					}
				}
			}
			
			
			if (cell.autoresizingMask & UIViewAutoresizingFlexibleHeight) {
				// flexible height
				if (!(cell.autoresizingMask & UIViewAutoresizingFlexibleTopMargin)) {
					// fixed top
					if (cell.autoresizingMask & UIViewAutoresizingFlexibleBottomMargin) {
						// flexible bottom
						height = cell.frame.size.height + (height - cell.frame.size.height) / 2; 
					} 
//					else
//					{
//						// vertical fill up
//					}

				} else {
					// flexible top
					CGFloat yOff = (height - cell.frame.size.height) / 2;
					oriY += yOff;
					height -= yOff;
				}

			} else {
				// fixed height
				if (!(cell.autoresizingMask & UIViewAutoresizingFlexibleTopMargin)) {
					// fixed top
					height = cell.frame.size.height;
				} else {
					if (!(cell.autoresizingMask & UIViewAutoresizingFlexibleBottomMargin)) {
						// fixed bottom
						oriY += (height - cell.frame.size.height);
						height = cell.frame.size.height;
					} else {
						// vertical middle
						CGFloat yOff = (height - cell.frame.size.height) / 2;
						oriY += yOff;
						height = cell.frame.size.height;
					}

				}

			}

		}

	}
	
	return CGRectMake(oriX, oriY, width, height);
}

- (NSIndexPath *)validIndexPathAtPoint:(CGPoint)point
{
//	CGFloat xOffset = point.x + self.contentOffset.x;
//	CGFloat yOffSet = point.y + self.contentOffset.y;
	CGFloat xOffset = point.x;
	CGFloat yOffSet = point.y;
	if (xOffset < 0 || yOffSet < 0) {
		return nil;
	}
	
	NSInteger ptCol = -1;
	CGFloat widths = 0;
	BOOL bCusColWid = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:widthForColumn:)]);
	for (NSInteger col = 0; col < _numberOfColumns; col++) {
		widths += (bCusColWid ? [self.listViewDelegate listView:self widthForColumn:col] : _columnWidth);
		if (xOffset <= widths) {
			ptCol = col;
			break;
		}
	} 
	if (ptCol == -1) {
		return nil;
	}
	
	NSInteger ptRow = -1;
	CGFloat heights = 0;
	BOOL bCusRowHei = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:heightForRow:)]);
	for (NSInteger row = 0; row < _numberOfRows; row++) {
		heights += (bCusRowHei ? [self.listViewDelegate listView:self heightForRow:row] : _rowHeight);
		if (yOffSet <= heights) {
			ptRow = row;
			break;
		}
	}
	if (ptRow == -1) {
		return nil;
	}
	
	return [NSIndexPath indexPathForRow:ptRow inColumn:ptCol];
}

- (BOOL)IsIndexPathValid:(NSIndexPath *)indexPath
{
	return (indexPath && (indexPath.row * _numberOfColumns + [indexPath column] < _numberOfCells));
}

-(CGRect)topLeftRectForIndexPath:(NSIndexPath *)indexPath
{
	CGRect rect = [self rectForCellAtIndexPath:indexPath];
	
//	CGFloat maxWidth = self.contentSize.width - (self.contentOffset.x + rect.origin.x);
//	CGFloat maxHeight = self.contentSize.height - (self.contentOffset.y + rect.origin.y);
	
	CGFloat maxWidth = self.contentSize.width - rect.origin.x;
	CGFloat maxHeight = self.contentSize.height - rect.origin.y;
	
	CGRect bound = [self selfBounds];
	
//	return CGRectMake(rect.origin.x + self.contentOffset.x, rect.origin.y + self.contentOffset.y, 
//					  (maxWidth < bound.size.width ? maxWidth : bound.size.width), 
//					  (maxHeight < bound.size.height ? maxHeight : bound.size.height));
	return CGRectMake(rect.origin.x, rect.origin.y, 
					  (maxWidth < bound.size.width ? maxWidth : bound.size.width), 
					  (maxHeight < bound.size.height ? maxHeight : bound.size.height));
}

-(CGRect)middleRectForIndexPath:(NSIndexPath *)indexPath
{
	CGRect rect = [self rectForCellAtIndexPath:indexPath];
	
	CGRect bound = [self selfBounds];
	
	CGFloat midX = rect.origin.x + rect.size.width / 2;
	CGFloat midY = rect.origin.y + rect.size.height / 2;
	CGFloat oriX = midX - bound.size.width / 2;
//	if (oriX + self.contentOffset.x < 0) {
//		oriX = -self.contentOffset.x;
//	}
	if (oriX < 0) {
		//oriX = -self.contentOffset.x;
		oriX = 0;
	}
	
	CGFloat oriY = midY - bound.size.height / 2;
//	if (oriY + self.contentOffset.y < 0) {
//		oriY = -self.contentOffset.y;
//	}
	if (oriY < 0) {
		//oriY = -self.contentOffset.y;
		oriY = 0;
	}
	CGFloat maxWidth = midX + bound.size.width / 2 - oriX;
	CGFloat maxHeight = midY + bound.size.height / 2 - oriY;
	
//	return CGRectMake(oriX + self.contentOffset.x, oriY + self.contentOffset.y, 
//					  (maxWidth < bound.size.width ? maxWidth : bound.size.width), 
//					  (maxHeight < bound.size.height ? maxHeight : bound.size.height));
	
	return CGRectMake(oriX, oriY, 
					  (maxWidth < bound.size.width ? maxWidth : bound.size.width), 
					  (maxHeight < bound.size.height ? maxHeight : bound.size.height));
}

-(CGRect)bottomRightRectForIndexPath:(NSIndexPath *)indexPath
{
	CGRect rect = [self rectForCellAtIndexPath:indexPath];
	
	CGRect bound = [self selfBounds];
	
	CGFloat destOriX = rect.origin.x + rect.size.width - bound.size.width;
//	if(destOriX + self.contentOffset.x < 0){
//		destOriX = -self.contentOffset.x;
//	}
	if(destOriX < 0){
		//destOriX = -self.contentOffset.x;
		destOriX = 0;
	}
	CGFloat destOriY = rect.origin.y + rect.size.height - bound.size.height;
//	if (destOriY + self.contentOffset.y < 0) {
//		destOriY = -self.contentOffset.y;
//	}
	if (destOriY < 0) {
		//destOriY = -self.contentOffset.y;
		destOriY = 0;
	}
//	return CGRectMake(destOriX + self.contentOffset.x, destOriY + self.contentOffset.y, 
//					  rect.origin.x + rect.size.width - destOriX,  
//					  rect.origin.y + rect.size.height - destOriY);
	
	return CGRectMake(destOriX, destOriY, 
					  rect.origin.x + rect.size.width - destOriX,  
					  rect.origin.y + rect.size.height - destOriY);
}

-(void)processSelectionForCell:(UIListViewCell *)cell
{
	NSIndexPath * indexPath = [self indexPathForCell:cell];
	if (indexPath != nil) {
		if (self.listViewDelegate  && [self.listViewDelegate respondsToSelector:@selector(listView:willSelectCellAtIndexPath:)]) {
			// process the custom indexpath going to be selected
			NSIndexPath * newIndexPath = [self.listViewDelegate listView:self willSelectCellAtIndexPath:indexPath];
			if (newIndexPath) {
				UIListViewCell * newCell = [self cellAtIndexPath:newIndexPath];
				if (newCell != nil ) {
					if (newCell != cell) {
						[cell setSelected:NO animated:NO];
						[newCell setSelected:YES animated:NO];
					}
					[self processSelectionsForIndexPath:newIndexPath];
				}
			}
		} else {
			// process current indexpath going to be selected
			[self processSelectionsForIndexPath:indexPath];
		}

	}
}

-(void)processSelectionsForIndexPath:(NSIndexPath *)indexPath
{
	NSNumber * index = [NSNumber numberWithUnsignedInt:(indexPath.row * _numberOfColumns + [indexPath column])];
	if ([_selectedIndexes containsObject:index] == NO) {
		SAFE_RELEASE(_pendingSelectionIndex);
		SAFE_RELEASE(_pendingDeselectionIndexes);
		_pendingSelectionIndex = [[NSNumber alloc] initWithUnsignedInteger:[index unsignedIntegerValue]];
		if (!_allowsMultiSelection) {
			_pendingDeselectionIndexes = [[NSArray alloc] initWithArray:_selectedIndexes];
		}
		[self processSelections];
	}
	else {
		if (_allowsMultiSelection) {
			SAFE_RELEASE(_pendingSelectionIndex);
			SAFE_RELEASE(_pendingDeselectionIndexes);
			_pendingDeselectionIndexes = [[NSArray alloc] initWithObjects:index, nil];
			[self processSelections];
		}
	}

}

-(void)processSelections
{
	BOOL cusWillDeselect = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:willDeselectCellAtIndexPath:)]);
	BOOL cusDidDeselect = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:didDeselectCellAtIndexPath:)]);
	

	for (NSNumber * index in _pendingDeselectionIndexes) {
		NSIndexPath * indexPath = [self indexPathForIndex:[index unsignedIntegerValue]];
		if (cusWillDeselect) {
			NSIndexPath * newPath = [self.listViewDelegate listView:self willDeselectCellAtIndexPath:indexPath];
			[self deselectIndexPath:newPath cusDidDeselect:cusDidDeselect];
		} else {
			[self deselectIndexPath:indexPath cusDidDeselect:cusDidDeselect];
		}
	}
	

	if(_pendingSelectionIndex != nil)
	{
		if (_allowsMultiSelection) {
			/// mutil select
			if ( ![_selectedIndexes containsObject:_pendingSelectionIndex]) {
				[_selectedIndexes addObject:_pendingSelectionIndex];
			}
		}
		else {
			/// single select
			[_selectedIndexes removeAllObjects]; 
			[_selectedIndexes addObject:_pendingSelectionIndex];
		}
		
		NSIndexPath * indexPath = [self indexPathForIndex:[_pendingSelectionIndex unsignedIntegerValue]];
		_latestSelectRow = indexPath.row;
		_latestSelectColum = [indexPath column];
		
		if (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:didSelectCellAtIndexPath:)]) {
			[self.listViewDelegate listView:self didSelectCellAtIndexPath:indexPath];
		}
	}

}

-(void)deselectIndexPath:(NSIndexPath *)indexPath cusDidDeselect:(BOOL)cusDidDeselect
{
	NSNumber * index = [NSNumber numberWithUnsignedInteger:(indexPath.row * _numberOfColumns + [indexPath column])];
	if ([_selectedIndexes containsObject:index]) {
		UIListViewCell * cell = [self cellAtIndexPath:indexPath];
		if (cell) {
			[cell setSelected:NO animated:NO];
		}
		[_selectedIndexes removeObject:index];
		if (cusDidDeselect) {
			[self.listViewDelegate listView:self didDeselectCellAtIndexPath:indexPath];
		}
	}
}

-(void)selectCell:(UIListViewCell *)cell
{
	if (cell.selected == YES) {
		[self processSelectionForCell:cell];
	}
}

-(void)insertCellAtIndex:(NSUInteger)index animated:(BOOL)animated
{
	if (index <= _numberOfCells) {
		_numberOfCells += 1;
		[self calRowAndColNum];
		//[self updateScrollSize];
		//NSIndexPath * insIndexPath = [self indexPathForIndex:index];
		//if (insIndexPath) {
		//if (index < _numberOfCells) 
		{
			NSNumber * insIndex = [NSNumber numberWithUnsignedInteger:index];
			if (animated) {
				[_insertItemsAnimated addObject:insIndex];
			}
			
			NSMutableDictionary * newVisibleCells = [[NSMutableDictionary alloc] initWithCapacity:1];
			NSArray * indexes = [_visibleCells allKeys];
			for (NSNumber * curIndex in indexes) {
				//NSIndexPath * indexPath = [self indexPathForIndex:[curIndex unsignedIntegerValue]];
				if ([curIndex unsignedIntegerValue] >= index) {
					// change the indexpaths after index
					//NSIndexPath * newIndexPath = [self increaseIndexPath:indexPath];
					if ([curIndex unsignedIntegerValue] + 1 < _numberOfCells) {
						id cell = [_visibleCells objectForKey:curIndex];
						[newVisibleCells setObject:cell forKey:[NSNumber numberWithUnsignedInteger:[curIndex unsignedIntegerValue] + 1]];
					} 
				} else {
					// save the indexpaths before index
					id cell = [_visibleCells objectForKey:curIndex];
					[newVisibleCells setObject:cell forKey:curIndex];
				}
			}
			[_visibleCells setDictionary:newVisibleCells];
			[newVisibleCells release];
			
			NSUInteger selCount = [_selectedIndexes count];
			for (NSUInteger i = 0; i < selCount; i++) {
				//NSIndexPath * selIndexPath = [_selectedIndexes objectAtIndex:i];
				NSNumber * selIndex = [_selectedIndexes objectAtIndex:i];
				if ([selIndex unsignedIntegerValue] >= index) {
					// change the selected indexpaths after index
					//NSIndexPath * newIndexPath = [self increaseIndexPath:selIndexPath];
					if ([selIndex unsignedIntegerValue] + 1 < _numberOfCells) {
						[_selectedIndexes replaceObjectAtIndex:i withObject:[NSNumber numberWithUnsignedInteger:([selIndex unsignedIntegerValue] + 1)]];
					}
				}
			}
			
			if (_singleEditingIndex) {
				NSUInteger oriIndex = [_singleEditingIndex unsignedIntegerValue];
				if (oriIndex + 1 < _numberOfCells) {
					[_singleEditingIndex release];
					_singleEditingIndex = [[NSNumber alloc] initWithUnsignedInteger:(oriIndex + 1)];
				}
			}
			
//			if (_updateCount == 0) {
//				[self removeInVisibleCellsWithAnimate:YES];
//				[self displayVisibleCellsWithAnimate:YES];
//			}
		}
	}
}

-(void)deleteCellAtIndex:(NSUInteger)index animated:(BOOL)animated;
{
//	NSIndexPath * delIndexPath = [self indexPathForIndex:index];
//	[self deleteCellAtIndexPath:delIndexPath animated:animated];
	
	NSNumber * delIndex = [NSNumber numberWithUnsignedInteger:index]; 
	UIListViewCell * delCell = [_visibleCells objectForKey:delIndex];
	if (delCell) {
		if (animated) {
			[_removeCellsAnimated addObject:delCell];
		} else {
			[_removeCells addObject:delCell];
		}
		[_visibleCells removeObjectForKey:delIndex];
	}
	
	if ([_selectedIndexes containsObject:delIndex]) {
		[_selectedIndexes removeObject:delIndex];
	}
	
	//NSUInteger index = [delIndex unsignedIntegerValue];
	NSMutableDictionary * newVisibleCells = [[NSMutableDictionary alloc] initWithCapacity:1];
	NSArray * indexes = [_visibleCells allKeys];
	for (NSNumber * curIndex in indexes) {
		if ([curIndex unsignedIntegerValue] > index) {
			// change the indexpaths after index
			id cell = [_visibleCells objectForKey:curIndex];
			[newVisibleCells setObject:cell forKey:[NSNumber numberWithUnsignedInteger:([curIndex unsignedIntegerValue] - 1)]];
		}
		else {
			// save the indexpaths before index
			id cell = [_visibleCells objectForKey:curIndex];
			[newVisibleCells setObject:cell forKey:curIndex];
		}
	}
	[_visibleCells setDictionary:newVisibleCells];
	[newVisibleCells release];
	
	NSUInteger selCount = [_selectedIndexes count];
	for (NSUInteger i = 0; i < selCount; i++) {
		//NSIndexPath * selIndexPath = [_selectedIndexes objectAtIndex:i];
		NSNumber * selIndex = [_selectedIndexes objectAtIndex:i];
		if ([selIndex unsignedIntegerValue] == index) {
			[_selectedIndexes removeObject:selIndex];
		} else if ([selIndex unsignedIntegerValue] > index) {
			// change the selected indexpaths after index
			//NSIndexPath * newIndexPath = [self decreaseIndexPath:selIndexPath];
			[_selectedIndexes replaceObjectAtIndex:i withObject:[NSNumber numberWithUnsignedInteger:([selIndex unsignedIntegerValue] - 1)]];
		}
	}
	
	if (_singleEditingIndex) {
		NSUInteger oriIndex = [_singleEditingIndex unsignedIntegerValue];
		if (oriIndex == index) {
			[self cancelSingleEditing];
//			[_singleEditingIndex release];
//			_singleEditingIndex = nil;
//			[self HandleCancelSingleEditMode];
		} else if (oriIndex > index && oriIndex > 0) {
			[_singleEditingIndex release];
			_singleEditingIndex = [[NSNumber alloc] initWithUnsignedInteger:(oriIndex - 1)];
		} 
	}
	
	_numberOfCells -= 1;
	[self calRowAndColNum];
	//[self updateScrollSize];
	//		if (_updateCount == 0) {
	//			[self removeInVisibleCellsWithAnimate:YES];
	//			[self displayVisibleCellsWithAnimate:YES];
	//		}

}

-(void)reloadCellAtIndex:(NSUInteger)index
{
//	NSIndexPath * relIndexPath = [self indexPathForIndex:index];
//	if (relIndexPath) {
//		<#statements#>
//	}
	
}


-(NSIndexPath *)indexPathForIndex:(NSUInteger)index
{
	if (index < _numberOfCells) {
		NSUInteger row = index / _numberOfColumns;
		NSUInteger colum = index - row * _numberOfColumns;
		return [NSIndexPath indexPathForRow:row inColumn:colum];
	}
	return nil;
}

-(void)updateItemOriPositions
{
	NSMutableArray * posMove = [[NSMutableArray alloc] initWithCapacity:1];
	for (NSUInteger i = 0; i < _numberOfCells; i++) {
		ItemInfo * item = [[ItemInfo alloc] initWithOriIndex:i step:0 flag:NO];
		[posMove addObject:item];
		[item release];
	}
	
	for (ItemOperation * itemOp in _itemOperations) {
		if (itemOp.type == OpTypeDelete) {
			// simulate the delete operation
			for (NSUInteger index = [itemOp.indexSet lastIndex]; index != NSNotFound; index = [itemOp.indexSet indexLessThanIndex:index]) {
				for (NSUInteger i = index + 1; i < [posMove count]; i++) {
					ItemInfo * item = [posMove objectAtIndex:i];
					item.step -= 1; 
					//[posMove  replaceObjectAtIndex:i withObject:[NSNumber numberWithInteger:newStep]];
				}
				if (index < [posMove count]) {
					[posMove removeObjectAtIndex:index];
				}
			}
			
		} else if (itemOp.type == OpTypeInsert) {
			// simulate the insert operation
			for (NSUInteger index = [itemOp.indexSet firstIndex]; index != NSNotFound; index = [itemOp.indexSet indexGreaterThanIndex:index]) {
				for (NSUInteger i = index; i < [posMove count]; i++) {
					ItemInfo * item = [posMove objectAtIndex:i];
					item.step += 1;
				}
				if (index < [posMove count]) {
					ItemInfo * newItem = [[ItemInfo alloc] initWithOriIndex:index step:0 flag:YES];
					[posMove insertObject:newItem atIndex:index];
					[newItem release];
				}
			}
		}
	}
	
	[_changeItemOriginalPositions removeAllObjects];
	for (ItemInfo * item in posMove) {
		if (item.newFlag == NO && item.step != 0) {
			NSIndexPath * oriIndexPath = [self indexPathForIndex:item.oriIndex];
			CGRect oriRect = [self rectForCellAtIndexPath:oriIndexPath];
			ItemPosition * changeItem = [[ItemPosition alloc] initWithIndex:(item.oriIndex + item.step) oriRect:oriRect oriIndex:item.oriIndex];
			[_changeItemOriginalPositions addObject:changeItem];
			[changeItem release];
		}
	}
	
	[posMove release];
}

-(void)processItemOperations
{
	_updateCount++;
	
	for (ItemOperation * itemOp in _itemOperations) {
		if (itemOp.type == OpTypeDelete) {
			// process the delete operation
			for (NSUInteger index = [itemOp.indexSet lastIndex]; index != NSNotFound; index = [itemOp.indexSet indexLessThanIndex:index]) {
				[self deleteCellAtIndex:index animated:itemOp.animated];
			}
			
		} else if (itemOp.type == OpTypeInsert) {
			// process the insert operation
			for (NSUInteger index = [itemOp.indexSet firstIndex]; index != NSNotFound; index = [itemOp.indexSet indexGreaterThanIndex:index]) {
				[self insertCellAtIndex:index animated:itemOp.animated];
			}
		}
	}
	
	[_itemOperations removeAllObjects];
	
	_updateCount--;
}

-(ItemPosition *)positionItemAtIndex:(NSUInteger)index
{
	for (ItemPosition * item in _changeItemOriginalPositions) {
		if (item.index == index) {
			return item;
		}
	}
	return nil;
}

-(void)processEditing
{
	NSArray * visibleObjects = [_visibleCells allValues];
	for (UIListViewCell * cell in visibleObjects) {
		if (_editing) {
			[self startRotateAnimationAtCell:cell shortPress:NO];
		} else {
			[self stopRotateAnimationAtCell:cell];
		}
		[cell setEditing:_editing animated:_animating];
	}
}

-(void)cancelSingleEditing
{
	if (_singleEditingIndex) {
		UIListViewCell * cell = [_visibleCells objectForKey:_singleEditingIndex];
		if (cell) {
			[cell setEditing:NO];
			[self stopRotateAnimationAtCell:cell];
		}
	}
	SAFE_RELEASE(_singleEditingIndex);
	//[self HandleCancelSingleEditMode];
}

#define KEY_ROTATEANIMATION @"Key_Rotateanimation"
static CGFloat rotateAngle = 0.01;
-(void)startRotateAnimationAtCell:(UIListViewCell *)cell shortPress:(BOOL)shortPress
{
	if (cell && [cell isEditing] == NO) {
		[self AddDeleteButtonToCell:cell shortPress:shortPress];
		CABasicAnimation *plusAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 
		plusAnimation.toValue = [NSNumber numberWithFloat:rotateAngle]; 
		plusAnimation.fromValue = [NSNumber numberWithFloat:-rotateAngle];
		plusAnimation.duration = 0.15; 
		plusAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
		plusAnimation.autoreverses = YES; 
		plusAnimation.repeatCount = FLT_MAX; 
		
		
		plusAnimation.delegate = self;
		cell.layer.edgeAntialiasingMask = kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge ;
		//cell.layer.edgeAntialiasingMask = 0;
		[cell.layer addAnimation:plusAnimation forKey:KEY_ROTATEANIMATION]; 
		
		//NSLog(@"startRotateAnimation:%x, AtCell:%x", plusAnimation, cell);
	}
}

-(void)stopRotateAnimationAtCell:(UIListViewCell *)cell;
{
	//NSLog(@"stopRotateAnimationAtCell:%x", cell);
	[self RemoveDeleteButtonFromCell:cell];
	[cell.layer removeAnimationForKey:KEY_ROTATEANIMATION];
	//[cell.shapeLayer removeAnimationForKey:KEY_ROTATEANIMATION];
}

#define MOVEANIMATIONID @"MoveAnimationID"
#define MOVEOUTANIMATIONID @"MoveOutAnimationID"
-(void)startMoveAnimationAtCell:(UIListViewCell *)cell destFrame:(CGRect)destFrame moveOut:(BOOL)moveOut index:(NSUInteger)index
{
	//NSLog(@"startMoveAnimationAtCell");
	
	NSString * animationID = moveOut ? (MOVEOUTANIMATIONID) : (MOVEANIMATIONID);
	
	[UIView beginAnimations:animationID context:(void *)index];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
	[UIView setAnimationDuration:1.0];
	[UIView setAnimationWillStartSelector:@selector(willStartMoveAnimation:context:)];
	[UIView setAnimationDidStopSelector:@selector(didStopMoveAnimation:finished:context:)];
	[UIView setAnimationDelegate:self];
	
	[cell setFrame:destFrame];
	
	[UIView commitAnimations];
}

#define KEY_SCALEANIMATION @"Key_ScaleAnimation"
#define KEY_SCALEANIMATIONREMOVE @"Key_ScaleAnimationRemove"
-(void)startScaleAnimationAtCell:(UIListViewCell *)cell toRemove:(BOOL)toRemove
{
	CABasicAnimation *plusAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; 
	plusAnimation.fromValue = [NSNumber numberWithFloat:(toRemove ? 1.0 : 0)];
	plusAnimation.toValue = [NSNumber numberWithFloat:(toRemove ? 0 : 1.0)]; 
	//plusAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
	plusAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
	//plusAnimation.autoreverses = NO; 
	//plusAnimation.repeatCount = 0;//FLT_MAX; 
	plusAnimation.delegate = self;
	cell.layer.edgeAntialiasingMask = 0;// kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge ;
	plusAnimation.fillMode = kCAFillModeForwards;
	if (toRemove == YES) {
		plusAnimation.duration = 0.3; 
		plusAnimation.removedOnCompletion = NO;
		
		[cell.layer addAnimation:plusAnimation forKey:KEY_SCALEANIMATIONREMOVE]; 
	} else {
		plusAnimation.duration = 0.8; 
		
		[cell.layer addAnimation:plusAnimation forKey:KEY_SCALEANIMATION]; 
	}

	
}

-(void)stopScaleAnimationAtCell:(UIListViewCell *)cell
{
	[cell.layer removeAnimationForKey:KEY_SCALEANIMATION];
}

/// UIView Animation delegate
- (void)willStartMoveAnimation:(NSString *)animationID context:(void *)context
{
}

- (void)didStopMoveAnimation:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
	if ([animationID isEqualToString:MOVEOUTANIMATIONID]) {
		//NSLog(@"didStopMoveAnimation finished: %d", [finished integerValue]);
		//NSIndexPath * indexPath = (NSIndexPath *)context; 
		NSUInteger uIndex = (NSUInteger)context;
		NSNumber * index = [NSNumber numberWithUnsignedInteger:uIndex];
		UIListViewCell * cell = [_visibleCells objectForKey:index];
		if (cell) {
			[cell removeFromSuperview];
			[self saveReuseCell:cell];
			[_visibleCells removeObjectForKey:index];
		} 
	} 
}

-(void)AddLongPressRecognizerToCell:(UIListViewCell *)cell
{
	if ([self LongPressAlreadyAddToCell:cell] == NO) {
		//NSLog(@"AddLongPressRecognizerToCell");
		UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
		[longPressRecognizer setMinimumPressDuration:2.0];
		[cell addGestureRecognizer:longPressRecognizer];        
		[longPressRecognizer release];
	}
}

-(void)handleLongPress:(UILongPressGestureRecognizer*)longPressRecognizer
{
	//NSLog(@"long press:%d", longPressRecognizer.state);
	if (longPressRecognizer.state == UIGestureRecognizerStateBegan) {
		_longPress = YES;	
		if (_editing == NO) {
			if (_listViewDelegate && [_listViewDelegate respondsToSelector:@selector(willChangeEditing:listView:)]) {
				[_listViewDelegate willChangeEditing:YES listView:self];
			}
			[self setEditing:YES animated:YES];
		//} else if (_editing == YES && _animating == YES) {
		} else {
			if (_listViewDelegate && [_listViewDelegate respondsToSelector:@selector(willChangeEditing:listView:)]) {
				[_listViewDelegate willChangeEditing:NO listView:self];
			}
			[self setEditing:NO animated:NO];
		} 

	} else if(longPressRecognizer.state == UIGestureRecognizerStateEnded){
		_longPress = NO;
		if ([longPressRecognizer.view isKindOfClass:[UIListViewCell class]]) {
			UIListViewCell * cell = (UIListViewCell *)longPressRecognizer.view;
			if (_allowsSelection == YES) {
				[self selectCell:cell];
			}
			if (_allowsLongPressAnimation == NO) {
				[cell removeGestureRecognizer:longPressRecognizer];
			}
		}
	}
}

-(BOOL)LongPressAlreadyAddToCell:(UIListViewCell *)cell
{
	BOOL bRet = NO;
	for (UIGestureRecognizer * gestureRecognizer in cell.gestureRecognizers) {
		if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
			bRet = YES;
			break;
		}
	}
	return bRet;
}

-(void)AddPanGestureRecognizerToCell:(UIListViewCell *)cell
{
	if ([self panGestureAlreadyAddToCell:cell] == NO) {
		//NSLog(@"AddPanGestureRecognizerToCell");
		UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
		//[panGestureRecognizer setMaximumNumberOfTouches:2];
		[panGestureRecognizer setMinimumNumberOfTouches:2];
		[panGestureRecognizer setCancelsTouchesInView:YES];
		//[panGestureRecognizer setDelegate:self];
		[cell addGestureRecognizer:panGestureRecognizer];        
		[panGestureRecognizer release];
	}
}

-(void)handlePanGesture:(UIPanGestureRecognizer *)panGestureRecognizer
{
	//NSLog(@"handlePanGesture");
	if (panGestureRecognizer.state == UIGestureRecognizerStateBegan) {
		if ([panGestureRecognizer.view isKindOfClass:[UIListViewCell class]]) {
			if (_singleEditingIndex == nil && _editing == NO) {
				UIListViewCell * cell = (UIListViewCell *)panGestureRecognizer.view;
				NSArray * indexes = [_visibleCells allKeysForObject:cell];
				if ([indexes count] > 0) {
					_singleEditingIndex = [[NSNumber alloc] initWithUnsignedInteger:[[indexes objectAtIndex:0] unsignedIntegerValue]];
					[self startRotateAnimationAtCell:cell shortPress:YES];
					[cell setEditing:YES animated:YES];
					[self AddShortPress];
					//[self HandleEnterSingleEditMode];
					
				}
			}
		} 
	} else if(panGestureRecognizer.state == UIGestureRecognizerStateEnded){
		
	}
}

-(BOOL)panGestureAlreadyAddToCell:(UIListViewCell *)cell
{
	BOOL bRet = NO;
	for (UIGestureRecognizer * gestureRecognizer in cell.gestureRecognizers) {
		if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
			bRet = YES;
			break;
		}
	}
	return bRet;
}

-(void)AddShortPress
{
	UILongPressGestureRecognizer *shortPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleShortPress:)];
	[shortPressGesture setMinimumPressDuration:0.02];
	[shortPressGesture setCancelsTouchesInView:YES];
    [self addGestureRecognizer:shortPressGesture];
    [shortPressGesture release];
}

-(void)handleShortPress:(UILongPressGestureRecognizer *)shortPressRecognizer
{
	if (shortPressRecognizer.view == self) {
		if (shortPressRecognizer.state == UIGestureRecognizerStateBegan) {
			[self cancelSingleEditing];

		} else if (shortPressRecognizer.state == UIGestureRecognizerStateEnded) {
			[self removeGestureRecognizer:shortPressRecognizer];
		}
	} 
}

-(IBAction)click_delete:(id)sender
{
	if ([[sender superview] isKindOfClass:[UIListViewCell class]]) {
		UIListViewCell * cell = (UIListViewCell *)[sender superview];
		NSArray * indexes = [_visibleCells allKeysForObject:cell];
		if ([indexes count] > 0) {
			NSNumber * index = [indexes objectAtIndex:0];
			//NSIndexSet * indexSet = [NSIndexSet indexSetWithIndex:[index unsignedIntegerValue]];
			//[self deleteCells:indexSet withCellAnimated:YES];
			if (self.dataSource && cell.editing == YES) {
				[self.dataSource listView:self 
					   commitEditingStyle:(UIListViewCellEditingStyle)UIListViewCellEditingStyleDelete 
						forRowAtIndexPath:[self indexPathForIndex:[index unsignedIntegerValue]]];
			}
		}
	}
}

-(IBAction)cancel_delete:(id)sender
{
	[self cancelSingleEditing];
}

#define DELETEBUTTONEDGE 50.0
-(void)AddDeleteButtonToCell:(UIListViewCell *)cell shortPress:(BOOL)shortPress
{
	BOOL bNeedToAdd = YES;
	for (UIButton * btn in _deleteButtons) {
		if ([btn superview] == cell) {
			bNeedToAdd = NO;
			break;
		}
	}
	if (bNeedToAdd == YES) {
		UIImage * delImage = nil;
		if (_delImageName != nil) {
			delImage = [UIUtil imageWithName:_delImageName];
		}
		CGFloat btnEdge = (delImage != nil) ? delImage.size.width : DELETEBUTTONEDGE;
		UIButton * delButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, btnEdge, btnEdge)];
		if (delImage != nil) {
			[delButton setImage:delImage forState:UIControlStateNormal];
		}
		delButton.autoresizingMask = UIViewAutoresizingNone;//UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
		[delButton addTarget:self action:@selector(click_delete:) forControlEvents:UIControlEventTouchUpInside];
		[delButton setBackgroundColor:[UIColor clearColor]];
		[delButton.layer setCornerRadius:(btnEdge / 2)];
		[delButton.layer setMasksToBounds:YES];
		[_deleteButtons addObject:delButton];
		
		if (shortPress == YES) {
			[delButton addTarget:self action:@selector(cancel_delete:) forControlEvents:UIControlEventTouchUpOutside];
			UILongPressGestureRecognizer *shortPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleShortPress:)];
			[shortPressGesture setMinimumPressDuration:0.01];
			[shortPressGesture setCancelsTouchesInView:NO];
			[delButton addGestureRecognizer:shortPressGesture];
			[shortPressGesture release];
		}
		
		[cell addSubview:delButton];
		
		[delButton release];
	}
}

-(void)RemoveDeleteButtonFromCell:(UIListViewCell *)cell
{
	for (UIButton * delBtn in _deleteButtons) {
		if ([delBtn superview] == cell) {
			[delBtn removeFromSuperview];
			[_deleteButtons removeObject:delBtn];
			break;
		}
	}
}

//-(void)HandleEnterSingleEditMode
//{
//	NSArray * visibles = [_visibleCells allValues];
//	for (UIListViewCell * cell in visibles) {
//		[cell ListviewEnterSingleEditMode];
//	}
//	NSArray * reuses = [_reusableTableCells allValues];
//	for (NSArray * cells in reuses) {
//		for (UIListViewCell * cell in cells) {
//			[cell ListviewEnterSingleEditMode];
//		}
//	}
//}

//-(void)HandleCancelSingleEditMode
//{
//	NSArray * visibles = [_visibleCells allValues];
//	for (UIListViewCell * cell in visibles) {
//		[cell setEditing:NO];
//	}
//	NSArray * reuses = [_reusableTableCells allValues];
//	for (NSArray * cells in reuses) {
//		for (UIListViewCell * cell in cells) {
//			[cell setEditing:NO];
//		}
//	}
//}

-(CellRange *)visibleRange
{
	CellRange * cellRange = [[[CellRange alloc] initWithLeft:0 top:0 right:0 bottom:0] autorelease];
	
	//CGRect selfbounds = [self selfBounds];
	
//	CGFloat oriX = 0;
//	BOOL cusColWidth = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:widthForColumn:)]);
//	for (NSUInteger i = 0; i < _numberOfColumns; i++) {
//		CGFloat colWid = (cusColWidth ? [self.listViewDelegate listView:self widthForColumn:i] : _columnWidth);
//		oriX += colWid; 
//		cellRange.left = i;
//		if (oriX + colWid > self.bounds.origin.x) {
//			break;
//		}
//	}
//	CGFloat boundsRight = self.bounds.origin.x + self.bounds.size.width;
//	for (NSUInteger i = cellRange.left + 1; i < _numberOfColumns; i++) {
//		oriX += (cusColWidth ? [self.listViewDelegate listView:self widthForColumn:i] : _columnWidth);
//		cellRange.right = i;
//		if (oriX > boundsRight) {
//			break;
//		}
//		
//	}
	
	if ([_colEdges count] == _numberOfColumns + 1) {
		for (NSUInteger i = 0; (i < _numberOfColumns) && [[_colEdges objectAtIndex:i + 1] floatValue] <= self.bounds.origin.x; i++) {
			cellRange.left = i;
		} 
		CGFloat boundsRight = self.bounds.origin.x + self.bounds.size.width;
		for (NSUInteger i = cellRange.left; (i < _numberOfColumns) && [[_colEdges objectAtIndex:i] floatValue] <= boundsRight; i++) {
			cellRange.right = i;
		}
	}

	
//	CGFloat oriY = 0;
//	BOOL cusRowHeiht = (self.listViewDelegate && [self.listViewDelegate respondsToSelector:@selector(listView:heightForRow:)]);
//	for (NSUInteger j = 0; j < _numberOfRows; j++) {
//		CGFloat rowHei = (cusRowHeiht ? [self.listViewDelegate listView:self heightForRow:j] : _rowHeight);
//		oriY += rowHei; 
//		cellRange.top = j;
//		if (oriY + rowHei > self.bounds.origin.y) {
//			break;
//		}
//	}
//	CGFloat boundsBottom = self.bounds.origin.y + self.bounds.size.height;
//	for (NSUInteger j = cellRange.top + 1; j < _numberOfRows; j++) {
//		oriY += (cusRowHeiht ? [self.listViewDelegate listView:self heightForRow:j] : _rowHeight);
//		cellRange.bottom = j;
//		if (oriY > boundsBottom) {
//			break;
//		}
//		
//	}
	if ([_rowEdges count] == _numberOfRows + 1) {
		for (NSUInteger i = 0; (i < _numberOfRows) && [[_rowEdges objectAtIndex:i + 1] floatValue] <= self.bounds.origin.y; i++) {
			cellRange.top = i;
		} 
		CGFloat boundsBottom = self.bounds.origin.y + self.bounds.size.height;
		for (NSUInteger i = cellRange.top; (i < _numberOfRows) && [[_rowEdges objectAtIndex:i] floatValue] <= boundsBottom; i++) {
			cellRange.bottom = i;
		}
	}
	
	return cellRange;
}

#pragma mark Overrided methods from UISCrollView
// Overridden by subclasses to customize the default behavior when a finger touches down in displayed content.
//- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
//{
//	BOOL bRet = [super touchesShouldBegin:touches withEvent:event inContentView:view];
//	return bRet;
//}

//Returns whether to cancel touches related to the content subview and start dragging.
//- (BOOL)touchesShouldCancelInContentView:(UIView *)view
//{
//	BOOL bRet = [super touchesShouldCancelInContentView:view];
//	return bRet;
//}


/// Data

// reloads everything from scratch. redisplays visible rows. because we only keep info about visible rows, this is cheap. will adjust offset if list shrinks
- (void)reloadData
{
	//if ([self.dataSource performSelector:@selector(numberOfColumnsInListView:)])
	NSUInteger oriCellNum = _numberOfCells;
	if (self.dataSource != nil) {	
		_numberOfColumns = [self.dataSource numberOfColumnsInListView:self];
		_numberOfRows = [self.dataSource numberOfRowsInListView:self];
		_numberOfCells = [self.dataSource numberOfCellsInListView:self];
	}
	[self calRowAndColNum];
	[self updateEdges];
	[self updateScrollSize];

	[self cancelSingleEditing];

	for (NSUInteger i = 0; i < oriCellNum; i++) {
		NSNumber * index = [NSNumber numberWithUnsignedInteger:i];
		if (_shoudRelayout == NO) {
			if ([_selectedIndexes containsObject:index]) {
				[_selectedIndexes removeObject:index];
			}
//			if ([_singleEditingIndex isEqualToNumber:index]) {
//				[_singleEditingIndex release];
//				_singleEditingIndex = nil;
//				[self HandleCancelSingleEditMode];
//			}
		}
		UIListViewCell * cell = [_visibleCells objectForKey:index];
		if (cell) {
			[cell removeFromSuperview];
			[self saveReuseCell:cell];
			[_visibleCells removeObjectForKey:index];
		}
	}

	[_visRange setRange:[self visibleRange]];
	[self removeInVisibleCellsWithAnimate:NO];
	[self displayVisibleCellsWithAnimate:NO];
	
	//[self updateScrollSize];
}

/// Info

- (NSInteger)numberOfColumns
{
	return _numberOfColumns;
}

- (NSInteger)numberOfRows
{
	return _numberOfRows;
}

- (CGRect)rectForCellAtIndexPath:(NSIndexPath *)indexPath
{	
	if ((indexPath.row + 1 < [_rowEdges count]) && ([indexPath column] + 1 < [_colEdges count])) {
		CGFloat oriX = [[_colEdges objectAtIndex:[indexPath column]] floatValue];
		CGFloat endX = [[_colEdges objectAtIndex:[indexPath column] + 1] floatValue];
		CGFloat oriY = [[_rowEdges objectAtIndex:indexPath.row] floatValue];
		CGFloat endY = [[_rowEdges objectAtIndex:indexPath.row + 1] floatValue];
		//return CGRectMake(oriX - self.contentOffset.x, oriY - self.contentOffset.y, endX - oriX, endY - oriY);
		return CGRectMake(oriX, oriY, endX - oriX, endY - oriY);
	}
	//return CGRectMake(- self.contentOffset.x, -self.contentOffset.y, 0, 0);
	return CGRectMake(0, 0, 0, 0);
}

// returns nil if point is outside list
- (NSIndexPath *)indexPathForCellAtPoint:(CGPoint)point
{
	NSIndexPath * indexPath = [self validIndexPathAtPoint:point];
	
	if (indexPath && indexPath.row * _numberOfColumns + [indexPath column] >= _numberOfCells) {
		return nil;
	}
	
	return indexPath;
}

// returns nil if cell is not visible
- (NSIndexPath *)indexPathForCell:(UIListViewCell *)cell
{
	NSArray * allKeys = [_visibleCells allKeysForObject:cell];
	if ([allKeys count] > 0) { // [allKeys count] == 1
		NSNumber * index = [allKeys objectAtIndex:0];
		NSIndexPath * indexPath = [self indexPathForIndex:[index unsignedIntegerValue]];
		return indexPath;
	}
	return nil;
}

// returns nil if rect not valid 
- (NSArray *)indexPathsForCellsInRect:(CGRect)rect
{
//	if (rect.origin.x + self.contentOffset.x < 0  || rect.origin.y + self.contentOffset.y < 0 ||
//		rect.origin.x + self.contentOffset.x + rect.size.width > self.contentSize.width ||
//		rect.origin.y + self.contentOffset.y + rect.size.height > self.contentSize.height) {
//		return nil;
//	}
	
	if (rect.origin.x < 0  || rect.origin.y < 0 ||
		rect.origin.x + rect.size.width > self.contentSize.width ||
		rect.origin.y + rect.size.height > self.contentSize.height) {
		return nil;
	}
	
	NSIndexPath * oriIndexPath = [self validIndexPathAtPoint:rect.origin];
	NSIndexPath * endIndexPath = [self validIndexPathAtPoint:CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height)];
	if (oriIndexPath && endIndexPath) {
		NSMutableArray * indexPaths = [NSMutableArray arrayWithCapacity:1];
		
		for (NSInteger row = oriIndexPath.row; row <= endIndexPath.row; row++) {
			for (NSInteger col = [oriIndexPath column]; col <= [endIndexPath column]; col++) {
				if (row * _numberOfColumns + col < _numberOfCells) {
					[indexPaths addObject:[NSIndexPath indexPathForRow:row inColumn:col]];
				}
			}
		}
		
		if ([indexPaths count] > 0) {
			return indexPaths;
		}
	}
	
	return nil;
}

// returns nil if cell is not visible or index path is out of range
- (UIListViewCell *)cellAtIndexPath:(NSIndexPath *)indexPath
{
	NSNumber * index = [NSNumber numberWithUnsignedInt:(indexPath.row * _numberOfColumns + [indexPath column])];
	return [_visibleCells objectForKey:index];
}

- (NSArray *)visibleCells
{
	return [_visibleCells allValues];
}

- (NSArray *)indexPathsForVisibleCells
{
	NSMutableArray * indexPaths = [NSMutableArray arrayWithCapacity:1];
	NSArray * indexes = [_visibleCells allKeys];
	for (NSNumber * index in indexes) {
		NSIndexPath * indexPath = [self indexPathForIndex:[index unsignedIntegerValue]];
		if (indexPath) {
			[indexPaths addObject:indexPath];
		}
	}
	return indexPaths;
}

- (void)scrollToCellAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UIListViewScrollPosition)scrollPosition animated:(BOOL)animated
{
	if ([self IsIndexPathValid:indexPath]) {
		switch (scrollPosition) {
			case UIListViewScrollPositionNone:
				break;
			case UIListViewScrollPositionTopLeft:
				[self scrollRectToVisible:[self topLeftRectForIndexPath:indexPath] animated:animated];
				break;
			case UIListViewScrollPositionMiddle:
				[self scrollRectToVisible:[self middleRectForIndexPath:indexPath] animated:animated];
				break;
			case UIListViewScrollPositionBottomRight:
				[self scrollRectToVisible:[self bottomRightRectForIndexPath:indexPath] animated:animated];
				break;
			default:
				break;
		}
	}
}

- (void)scrollToNearestSelectedCellAtScrollPosition:(UIListViewScrollPosition)scrollPosition animated:(BOOL)animated
{
	if ([_selectedIndexes count] > 0) {
		NSIndexPath * indexPath = [NSIndexPath indexPathForRow:_latestSelectRow inColumn:_latestSelectColum];
		if ([self IsIndexPathValid:indexPath]) {
			switch (scrollPosition) {
				case UIListViewScrollPositionNone:
					break;
				case UIListViewScrollPositionTopLeft:
					[self scrollRectToVisible:[self topLeftRectForIndexPath:indexPath] animated:animated];
					break;
				case UIListViewScrollPositionMiddle:
					[self scrollRectToVisible:[self middleRectForIndexPath:indexPath] animated:animated];
					break;
				case UIListViewScrollPositionBottomRight:
					[self scrollRectToVisible:[self bottomRightRectForIndexPath:indexPath] animated:animated];
					break;
					
				default:
					break;
			}
		}
	}
}

/// Row insertion/deletion/reloading.

// allow multiple insert/delete of rows and sections to be animated simultaneously. Nestable
- (void)beginUpdates
{
	_updateCount++; 
}

// only call insert/delete/reload calls or change the editing state inside an update block.  otherwise things like row count, etc. may be invalid.
- (void)endUpdates
{
	if (_updateCount > 0) {
		_updateCount--;
	}
	[self updateItemOriPositions];
	[self processItemOperations];
	[self calRowAndColNum];
	[self updateEdges];
	[self updateScrollSize];
	[_visRange setRange:[self visibleRange]];
	[self removeInVisibleCellsWithAnimate:YES];
	[self displayVisibleCellsWithAnimate:YES];
	
	//[self updateScrollSize];
	
	[_changeItemOriginalPositions removeAllObjects];
	
	if (_numberOfCells == 0) {
		_editing = NO;
		_animating = NO;
	}
}

- (void)insertCells:(NSIndexSet *)cells withCellAnimated:(BOOL)animated
{
	ItemOperation * itemOp = [[ItemOperation alloc] initWithType:OpTypeInsert indexSet:cells animated:animated];
	[_itemOperations addObject:itemOp];
	[itemOp release];
	
	if (_updateCount == 0) {
		[self updateItemOriPositions];
		[self processItemOperations];
		[self updateEdges];
		[self updateScrollSize];
		[_visRange setRange:[self visibleRange]];
		[self removeInVisibleCellsWithAnimate:YES];
		[self displayVisibleCellsWithAnimate:YES];
		
		//[self updateScrollSize];
		
		[_changeItemOriginalPositions removeAllObjects];
	}
}

- (void)deleteCells:(NSIndexSet *)cells withCellAnimated:(BOOL)animated
{
	ItemOperation * itemOp = [[ItemOperation alloc] initWithType:OpTypeDelete indexSet:cells animated:animated];
	[_itemOperations addObject:itemOp];
	[itemOp release];
	
	if (_updateCount == 0) {
		[self updateItemOriPositions];
		[self processItemOperations];
		[self updateEdges];
		[self updateScrollSize];
		[_visRange setRange:[self visibleRange]];
		[self removeInVisibleCellsWithAnimate:YES];
		[self displayVisibleCellsWithAnimate:YES];
		
		//[self updateScrollSize];
		
		[_changeItemOriginalPositions removeAllObjects];
		
		if (_numberOfCells == 0) {
			_editing = NO;
			_animating = NO;
		}
	}
}

- (void)reloadCells:(NSIndexSet *)cells withCellAnimated:(BOOL)animated
{
//	for (NSUInteger index = [cells firstIndex]; index != NSNotFound; index = [cells indexGreaterThanIndex:index]) {
//		[self reloadCellAtIndex:index];
//	}
}

/// Editing. When set, rows show delete/reorder controls

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
	[self cancelSingleEditing];
	_editing = editing;
	_animating = animated;
	[self processEditing];
}

/// Selection
// return nil or index path representing section and row of selection.
- (NSIndexPath *)indexPathForSelectedCell
{
	//return _selectedIndexes;
	// single select
	if ([_selectedIndexes count] > 0) {
		
		return [self indexPathForIndex:[[_selectedIndexes objectAtIndex:0] unsignedIntegerValue]];
	}
	return nil;
}

- (NSArray *)indexPathForSelectedCells
{
	if ([_selectedIndexes count] > 0) {
		NSMutableArray * selects = [NSMutableArray array];
		//return [NSArray arrayWithArray:_selectedIndexes];
		for (NSNumber * index in _selectedIndexes) {
			NSIndexPath * indexPath = [self indexPathForIndex:[index unsignedIntegerValue]]; 
			if (indexPath) {
				[selects addObject:indexPath];
			}
		}
		return selects;
	}
	return nil;
}

// Selects and deselects cells. These methods will not call the delegate methods (-listView:willSelectCellAtIndexPath: or listView:didSelectCellAtIndexPath:), nor will it send out a notification.
- (void)selectCellAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UIListViewScrollPosition)scrollPosition
{
	if ([self IsIndexPathValid:indexPath]) {
		NSNumber * index = [NSNumber numberWithUnsignedInteger:(indexPath.row * _numberOfColumns + [indexPath column])];
		if (_allowsMultiSelection) {
			///mutil select
			if (index && ![_selectedIndexes containsObject:index]) {
				[_selectedIndexes addObject:index];
			}
			
			UIListViewCell * cell = [self cellAtIndexPath:indexPath];
			if (cell) {
				[cell setSelected:YES animated:animated];
			}
		}
		else{
			/// single select
			[_selectedIndexes removeAllObjects];
			[_selectedIndexes addObject:index];
		}


		_latestSelectRow = indexPath.row; 
		_latestSelectColum = [indexPath column];
		
		[self scrollToCellAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
	}
} 

- (void)deselectCellAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated
{
	if ([self IsIndexPathValid:indexPath]) {
		UIListViewCell * cell = [self cellAtIndexPath:indexPath];
		if (cell) {
			[cell setSelected:NO animated:animated];
		}
		NSNumber * index = [NSNumber numberWithUnsignedInteger:(indexPath.row * _numberOfColumns + [indexPath column])];
		[_selectedIndexes removeObject:index];
		if ([_pendingSelectionIndex isEqual:index]) {
			SAFE_RELEASE(_pendingSelectionIndex);
			if ([_selectedIndexes count] > 0) {
				NSNumber * lastIndex = [_selectedIndexes lastObject];
				NSIndexPath * last = [self indexPathForIndex:[lastIndex unsignedIntegerValue]];
				_latestSelectRow = last.row;
				_latestSelectColum = [last column];
			}
		}
	}
}

// Used by the delegate to acquire an already allocated cell, in lieu of allocating a new one.
- (UIListViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier
{
	NSMutableArray * reusableCells = [_reusableTableCells objectForKey:identifier];
	if ([reusableCells count] > 0) {
		UIListViewCell * cell = [[[reusableCells objectAtIndex:0] retain] autorelease];
		//NSLog(@"resuable cell retain count: %d", [cell retainCount]);
		[reusableCells removeObjectAtIndex:0];
		//NSLog(@"resuable cell retain count: %d", [cell retainCount]);
		[cell prepareForReuse];
		return cell;
	}
	return nil;
}

#pragma mark NSCoding

- (void)encodeWithCoder:(NSCoder *)aCoder
{
	[super encodeWithCoder:aCoder];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
	self = [super initWithCoder:aDecoder];
	if (self) {
		[self Initialize];
	}
	return self;
}

#pragma mark UIScrollViewDelegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) {
		[_outsideDelegate scrollViewDidEndDecelerating:scrollView];
	}
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) {
		[_outsideDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
	}
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) {
		[_outsideDelegate scrollViewDidEndScrollingAnimation:scrollView];
	}
}

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) {
		[_outsideDelegate scrollViewDidEndZooming:scrollView withView:view atScale:scale];
	}
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
	//NSLog(@"ScrollStart:%.2f", [[NSDate date] timeIntervalSince1970]);
	CellRange * visRange = [self visibleRange];
	if (visRange.left != _visRange.left || visRange.right != _visRange.right ||
		visRange.top != _visRange.top || visRange.bottom != _visRange.bottom) {
		[_visRange setRange:visRange];
		[self removeInVisibleCellsWithAnimate:NO];
		[self displayVisibleCellsWithAnimate:NO];
	}
	
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
		[_outsideDelegate scrollViewDidScroll:scrollView];
	}
	//NSLog(@"ScrollEnd: %.2f", [[NSDate date] timeIntervalSince1970]);
}

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) {
		[_outsideDelegate scrollViewDidScrollToTop:scrollView];
	}
}

- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewDidZoom:)]) {
		[_outsideDelegate scrollViewDidZoom:scrollView];
	}
}

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) {
		return [_outsideDelegate scrollViewShouldScrollToTop:scrollView];
	}
	
	return YES;
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) {
		[_outsideDelegate scrollViewWillBeginDecelerating:scrollView];
	}
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) {
		[_outsideDelegate scrollViewWillBeginDragging:scrollView];
	}
}

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) {
		[_outsideDelegate scrollViewWillBeginZooming:scrollView withView:view];
	}
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
	UIView * view = nil;

	if (_outsideDelegate && [_outsideDelegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) {
		view = [_outsideDelegate viewForZoomingInScrollView:scrollView];
	}
	
	return view;
}

#pragma mark CAAnimationDelegate
- (void)animationDidStart:(CAAnimation *)theAnimation
{
	
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
	if ([theAnimation isKindOfClass:[CABasicAnimation class]]) {
		//NSLog(@"animationDidStop:%x, flag:%d", theAnimation, flag);
		for (UIListViewCell * cell in _removeCellsAnimated) {
			if (cell && ([cell.layer animationForKey:KEY_SCALEANIMATIONREMOVE] == theAnimation)) {
				[cell.layer removeAnimationForKey:KEY_SCALEANIMATIONREMOVE];
				[cell removeFromSuperview];
				[self saveReuseCell:cell];
				[_removeCellsAnimated removeObject:cell];
				break;
			}
		}
	}
}

- (void)setContentInset:(UIEdgeInsets)insets
{
	UIEdgeInsets newInsets = UIEdgeInsetsMake(insets.top + _scrollInset.top, insets.left + _scrollInset.left, 
											  insets.bottom + _scrollInset.bottom, insets.right + _scrollInset.right);
	[super setContentInset:newInsets];
}

- (void)setScrollInset:(UIEdgeInsets)insets
{
	_scrollInset = insets;
	[super setContentInset:insets];
}

@end


@implementation NSIndexPath (UIListView)

+ (NSIndexPath *)indexPathForRow:(NSUInteger)row inColumn:(NSUInteger)column
{
	return [NSIndexPath indexPathForRow:row inSection:column];
}

- (NSUInteger)column
{
	return self.section;
}

@end


@implementation ItemPosition

@synthesize index = _index;
@synthesize oriRect = _oriRect;
@synthesize oriIndex = _oriIndex;

- (id)initWithIndex:(NSUInteger)theIndex oriRect:(CGRect)theRect oriIndex:(NSUInteger)theOriIndex
{
	self = [super init];
	
	_index = theIndex;
	_oriRect = theRect;
	_oriIndex = theOriIndex;
	
	return self;
}

- (void)dealloc
{
	[super dealloc];
}

@end


@implementation ItemOperation

@synthesize type = _type;
@synthesize indexSet = _indexSet;
@synthesize animated = _animated;

- (id)initWithType:(OperationType)theType indexSet:(NSIndexSet *)theIndexSet animated:(BOOL)animatedFlag
{
	self = [super init];
	
	_type = theType;
	if(theIndexSet)
	{
		_indexSet = [[NSIndexSet alloc] initWithIndexSet:theIndexSet];
	}
	_animated = animatedFlag;
	
	return self;
}

- (void)dealloc
{
	SAFE_RELEASE(_indexSet);
	[super dealloc];
}

@end


@implementation ItemInfo

@synthesize newFlag = _newFlag;
@synthesize step = _step;
@synthesize oriIndex = _oriIndex;

- (id)initWithOriIndex:(NSUInteger)theIndex step:(NSInteger)theStep flag:(BOOL)theNewFlag
{
	self = [super init];
	
	_newFlag = theNewFlag;
	_step = theStep;
	_oriIndex = theIndex;
	
	return self;
}

- (void)dealloc
{
	[super dealloc];
}

@end


@implementation CellRange

@synthesize left = _left;
@synthesize top = _top;
@synthesize right = _right;
@synthesize bottom = _bottom;

- (id)initWithLeft:(NSUInteger)theLeft top:(NSUInteger)theTop right:(NSUInteger)theRight bottom:(NSUInteger)theBottom
{
	self = [super init];
	
	_left = theLeft;
	_top = theTop;
	_right = theRight;
	_bottom = theBottom;
	
	return self;
}

- (void)setRange:(CellRange *)range
{
	if (range) {
		_left = range.left;
		_right = range.right;
		_top = range.top;
		_bottom = range.bottom;
	}
}

- (void)dealloc
{
	[super dealloc];
}

@end


